package com.slt.concurrency.mashibing2019.juc.c_005_AtomicXXX.exercise;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

/**
 * 测试 cas 与 sync 的效率对比
 * <p>
 * LongAdder ： 在并发特别高时候，效率比较高
 * 分段锁原理
 */
public class AtomicVsSyncVsLongAdder {
    static Long count1 = 0l;
    static AtomicLong count2 = new AtomicLong(0);
    //Creates a new adder with initial sum of zero.
    static LongAdder count3 = new LongAdder();

    void millSleep(int mills) {
        try {
            Thread.sleep(mills);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        testAtomicLong();
        testSync();
        testLongAdder();
    }
    private static void testAtomicLong() throws InterruptedException {
        Thread[] threads = new Thread[1000];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(()->{
                for (int j = 0; j < 100000; j++) {
                    count2.incrementAndGet();
                }
            });
        }
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < threads.length; i++) {
            threads[i].start();
        }
        for (int i = 0; i < threads.length; i++) {
            threads[i].join();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("atomicLong: " + (endTime - startTime) + " ms");
    }

    private static void testSync() throws InterruptedException {
        Thread[] threads = new Thread[1000];
        Object lock = new Object();
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(()->{
                for (int j = 0; j < 100000; j++) {
                    synchronized (lock){
                        count1++;
                    }
                }
            });
        }
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < threads.length; i++) {
            threads[i].start();
        }
        for (int i = 0; i < threads.length; i++) {
            threads[i].join();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("synchronized: " + (endTime - startTime) + " ms");
    }


    private static void testLongAdder() throws InterruptedException {
        Thread[] threads = new Thread[1000];
        Object lock = new Object();
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(()->{
                for (int j = 0; j < 100000; j++) {
                    count3.increment();
                }
            });
        }
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < threads.length; i++) {
            threads[i].start();
        }
        for (int i = 0; i < threads.length; i++) {
            threads[i].join();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("longAdder: " + (endTime - startTime) + " ms");
    }

}
